package com.example.feigntest.customconfig.requestinterceptor;

import cn.hutool.core.util.ArrayUtil;
import cn.hutool.json.JSONObject;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.Map;

/**
 * 描述：Feign HTTP 请求调用的拦截器
 *
 * @author YangQun by 2020/10/17
 */
public class CustomFeignRequestInterceptor implements RequestInterceptor {
    private final Logger log = LoggerFactory.getLogger(getClass());

    private static final Charset UTF_8 = StandardCharsets.UTF_8;

    public static final String CUSTOM_HEADER = "appId";


    /**
     * 根据 {@link RequestTemplate} 你可以做一些 Feign 调用的统一修改,如:添加 header auth 认证, 修改请求体内容
     *
     * @param template 封装了 http 请求的所有信息
     */
    @Override
    public void apply(RequestTemplate template) {
        log.info("CustomFeignRequestInterceptor - 请求进入, 请求头数量为[{}], 请求体字节大小为[{}]", template.headers().size(), ArrayUtil.length(template.body()));

        // 新添加头信息
        template.header(CUSTOM_HEADER, "Custom App Id From RequestInterceptor");

        // 获取头信息
        Map<String, Collection<String>> httpHeaders = template.headers();

        if (bodyIsJson(httpHeaders)){
            String bodyJsonStr = new String(template.body(), UTF_8);
            log.debug("请求体原内容: {}", bodyJsonStr);

            // 对原请求体内容做修改
            JSONObject jsonObject = new JSONObject(bodyJsonStr);
            jsonObject.set("customJsonKeyFromRequestTemplate" ,"customJsonValueFromRequestTemplate");

            template.body(jsonObject.toString().getBytes(UTF_8), UTF_8);
        }

        log.info("CustomFeignRequestInterceptor - 执行完毕, 请求头数量为[{}], 请求体字节大小为[{}]", template.headers().size(), template.body().length);
    }


    /**
     * 根据头信息判断请求是不是 json 格式
     * @param httpHeaders 所有请求头
     * @return true:是 / false:不是
     */
    private boolean bodyIsJson(Map<String, Collection<String>> httpHeaders) {
        return httpHeaders.keySet()
                .stream()
                .anyMatch(header -> {
                    if (HttpHeaders.CONTENT_TYPE.equalsIgnoreCase(header)) {
                        return httpHeaders.get(header)
                                .stream()
                                .anyMatch(value -> value.contains(MediaType.APPLICATION_JSON_VALUE));
                    } else {
                        return false;
                    }
                });
    }
}
